
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: MapReader.java 218 2009-11-19 18:01:57Z archie.cobbs $
 */

package org.dellroad.sidekar.annotation;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;

import org.dellroad.sidekar.schema.model.MapFieldModel;
import org.dellroad.sidekar.schema.model.SimpleFieldModel;

/**
 * Introspects {@link SidekarMap} annotations.
 */
class MapReader extends AbstractReader {

    /**
     * Look for {@link SidekarMap} annotations and process them.
     */
    @Override
    public void process(Class<?> entityClass, Set<Method> methods) {
        for (Method method : methods) {
            SidekarMap sidekarMap = method.getAnnotation(SidekarMap.class);
            if (sidekarMap != null)
                this.processMapAnnotation(sidekarMap, method);
        }
    }

    private void processMapAnnotation(SidekarMap a, Method method) {

        // Record info
        MapFieldModel fieldModel = new MapFieldModel();
        this.recordGetterModel(a, method, a.value(), fieldModel);

        // Infer key and value info from return type
        Type rtype = method.getGenericReturnType();
        if (!(rtype instanceof ParameterizedType))
            throw new InvalidAnnotationException(a, method, "method does not return a generic collection type");
        Type[] ptypes = ((ParameterizedType)rtype).getActualTypeArguments();
        if (getRawType(a, method, rtype) != Map.class || ptypes.length != 2)
            throw new InvalidAnnotationException(a, method, "method does not return Map<K, V>");
        SimpleFieldModel keyModel = createSimpleField(a, method, ptypes[0], true);
        SimpleFieldModel valueModel = createSimpleField(a, method, ptypes[1], true);

        // Record map type info
        fieldModel.setKeyModel(keyModel);
        fieldModel.setValueModel(valueModel);
        fieldModel.setAccessMethod(method);
        this.log.debug("found " + a + " annotation on method " + method);
    }
}

